package mango;

import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.Properties;
import mango.functions.FuncString;
import mango.orm.DBSessionFactory;
import mango.orm.connect.Connector;
import mango.utils.Logger;
import mango.utils.SimpleLogger;

public final class Mango {
    private static final String PROJECT_NAME = Mango.class.getSimpleName();
    private static final String PROJECT_NAME_LOWER = PROJECT_NAME.toLowerCase();
    public static final String ENCODING = PROJECT_NAME_LOWER + ".sys.encoding";
    public static final String TEMP = PROJECT_NAME_LOWER + ".sys.temp";
    public static final String DATEFORMAT = PROJECT_NAME_LOWER + ".sys.dateFormat";
    public static final String SHOWSQL = PROJECT_NAME_LOWER + ".sys.showsql";
    public static final String MAX_DB_HANDLER = PROJECT_NAME_LOWER + "sys.maxdbhandler";

    public static final String ACTION_PACKAGE = PROJECT_NAME_LOWER + ".web.actionPackage";
    public static final String INFO_MAKER = PROJECT_NAME_LOWER + ".web.infomaker";
    public static final String CONNECTOR = PROJECT_NAME_LOWER + ".connector";
    private static Logger LOG;
    private static Properties prop = new Properties();
    private static boolean initial = false;
    
    public static void setLog(Logger log) {
        LOG = log;
    }
    
    public static Logger getLog(){
        if (LOG == null) {
            LOG = new SimpleLogger();
        }
        return LOG;
    }
    
    public static boolean initialize() {
        return Mango.initialize(PROJECT_NAME_LOWER + ".properties");
    }

    public static boolean initialize(String config) {
        InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream(config);
        if (in == null) {
            throw new ExceptionInInitializerError("can't read the config file : " + config);
        }
        try {
            Mango.prop = new Properties();
            Mango.prop.load(in);
            Mango.initial = true;
            validateInitial();
            return true;
        }
        catch (IOException e) {
            Mango.initial = false;
            throw new ExceptionInInitializerError(e);
        }
        catch (ExceptionInInitializerError e) {
            Mango.initial = false;
            throw e;
        }
        finally {
            if (in != null) {
                try {
                    in.close();
                }
                catch (IOException e) {
                }
            }
        }
    }

    private static void validateInitial() {
        if (prop == null) {
            throw new ExceptionInInitializerError(PROJECT_NAME + " initialize error");
        }
        if (FuncString.isBlank(getProperty(CONNECTOR))) {
            throw new ExceptionInInitializerError("must config a connector");
        }
        if (FuncString.isBlank(ACTION_PACKAGE)) {
            throw new ExceptionInInitializerError("must config action package");
        }
        if (FuncString.isBlank(ENCODING)) {
            prop.setProperty(ENCODING, "UTF-8");
        }
        if (FuncString.isBlank(DATEFORMAT)) {
            prop.setProperty(DATEFORMAT, "yyyy-MM-dd");
        }
        if (FuncString.isBlank(TEMP)) {
            prop.setProperty(TEMP, System.getProperty("user.home") + ".temp");
        }
    }

    public static void trace() {
        Enumeration<Object> keys = prop.keys();
        while (keys.hasMoreElements()) {
            String key = (String) keys.nextElement();
            getLog().info(key + "|" + prop.getProperty(key));
        }
    }

    public static boolean initialized() {
        return Mango.initial;
    }

    public static String getProperty(String key) {
        if (!Mango.initialized()) {
            throw new ExceptionInInitializerError(PROJECT_NAME + " is Not initialized!");
        }
        return Mango.prop.getProperty(key);
    }
    
    public static void close() {
        DBSessionFactory.closeAll();
        Connector.closeAll();
        prop.clear();
        initial = false;
    }
}
